package main

import (
	"fmt"
	"mymath"
)

// 2.4 流程控制
func main() {
	// 2.4.1 条件语句
	//	a := int32(12)
	//	b := int32(13) // 转义
	// 在 if 之后，条件语句之前，可以添加变量初始化语句，使用 ; 间隔；
	//	if a < b {
	//		fmt.Println("a < b")
	//	} else {
	//		fmt.Println("a >= b")
	//	}
	//	fmt.Println(example(12))

	// 2.4.2 选择语句
	//	Num := 4
	//	switch i {
	//	case 0:
	//		fmt.Printf("0")
	//	case 1:
	//		fmt.Printf("1")
	//	case 2:
	//		fallthrough
	//	case 3:
	//		fmt.Printf("3")
	//	case 4, 5, 6:
	//		fmt.Printf("4, 5, 6")
	//	default:
	//		fmt.Printf("Default")
	//	}
	// 与C语言等规则相反，Go语言不需要用 break 来明确退出一个 case
	// 只有在 case 中明确添加 fallthrough 关键字，才会继续执行紧跟的下一个 case ；
	//	switch {
	//	case 0 <= Num && Num <= 3:
	//		fmt.Printf("0-3")
	//	case 4 <= Num && Num <= 6:
	//		fmt.Printf("4-6")
	//		fallthrough
	//	case 7 <= Num && Num <= 9:
	//		fmt.Printf("7-9")
	//	}

	//2.4.3 循环语句
	// Go语言中的循环语句只支持 for 关键字，而不支持 while 和 do-while结构
	//	sum := 0
	//	for i := 0; i < 10; i++ {
	//		sum += i
	//	}
	//	fmt.Println(sum)

	// 无线循环
	//	sum := 0
	//	for {
	//		sum += 1
	//		if sum > 100 {
	//			break
	//		}
	//	}
	//	fmt.Println(sum)

	// 在条件表达式中也支持多重赋值，如下所示：
	//	x := []int{4, 1, 3, 2, 1}
	//	for i, j := 0, len(x)-1; i < j; i, j = i+1, j-1 {
	//		x[i], x[j] = x[j], x[i]
	//	}
	//	fmt.Println(x)

	// Go语言的 for 循环同样支持 continue 和 break 来控制循环，但是它提供了一个更高级的break ，可以选择中断哪一个循环，如下例：
	//J:
	//	for j := 0; j < 5; j++ {
	//		for i := 0; i < 10; i++ {
	//			if i > 6 {
	//				break J //现在终止的是j 循环，而不是i的那个
	//				//				break //现在终止的是j 循环，而不是i的那个
	//			}
	//			fmt.Println(i)
	//		}
	//	}

	// 2.4.4 跳转语句
	//	myfunc()

	// 2.5 函数c := mymath.Add(1, 2)
	c := mymath.Add2(1, 2)
	fmt.Println(c)
	// 1. 不定参数类型
	//	myfunc2(2, 3, 4)

	// 3. 任意类型的不定参数
	//	myfunc4(2, 3, 4)
	//	var v1 int = 1
	//	var v2 int64 = 234
	//	var v3 string = "hello"
	//	var v4 float32 = 1.234
	//	MyPrintf(v1, v2, v3, v4)

	// 2.5.5 匿名函数与闭包
	// 1. 匿名函数 匿名函数可以直接赋值给一个变量或者直接执行:
	//	f := func(x, y int) int {
	//		return x + y
	//	}
	//	fmt.Println(f(2, 2))

	//	func(ch int) {
	//		fmt.Println(ch)
	//	}(1) // 花括号后直接跟参数列表表示函数调用

	// 2. 闭包
	// 这些函数可以存储到变量中作为参数传递给其他函数，最重要的是能够被函数动态创建和返回。
	// /Go语言中的闭包同样也会引用到函数外的变量。闭包的实现确保只要闭包还被使用，那么
	// 被闭包引用的变量会一直存在
	j := 5
	a := func() func(out int) {
		i := 10
		//		fmt.Printf("i, j, out: %d, %d, %d\n", i, j, out) // error
		return func(out int) {
			i *= 2
			fmt.Printf("i, j, out: %d, %d, %d\n", i, j, out)
		}
	}()

	a(2)
	j *= 2

	a(2)
}

// 1. 不定参数类型
// 2. 不定参数的传递
func myfunc2(args ...int) {
	// 按原样传递
	myfunc3(args...)

	// 传递片段，实际上任意的int slice都可以传进去
	myfunc3(args[1:]...)
}

func myfunc3(args ...int) {
	for _, arg := range args {
		fmt.Println(arg)
	}
}

// 3. 任意类型的不定参数
// 用 interface{} 传递任意类型数据是Go语言的惯例用法。
func myfunc4(args ...interface{}) {
	for _, arg := range args {
		fmt.Println(arg)
	}
}

// 3. 任意类型的不定参数
func MyPrintf(args ...interface{}) {
	for _, arg := range args {
		switch arg.(type) {
		case int:
			fmt.Println(arg, "is an int value.")
		case string:
			fmt.Println(arg, "is a string value.")
		case int64:
			fmt.Println(arg, "is an int64 value.")
		default:
			fmt.Println(arg, "is an unknown type.")
		}
	}
}

func myfunc() {
	i := 0
HERE:
	fmt.Println(i)
	i++
	if i < 10 {
		goto HERE
	}
}
func example(x int32) int32 {
	if x == 0 {
		return 5
	} else {
		return x
	}
}
